﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using blackhouse.WebNemo.Data;
using blackhouse.WebNemo.Business.Exceptions;

namespace blackhouse.WebNemo.Business.Groups {
    public class GroupRecordQuery {

        #region Fields

        private IGroup group;
        private List<WhereColumn> where = new List<WhereColumn>();
        internal QueryType type = QueryType.QueryWithWhereClauses;
        internal ProcedureQuery query;
        private Dictionary<int, string> groupTableMap = new Dictionary<int, string>();

        #endregion

        #region Properties

        internal SelectColumn[] SelectColumns {
            get;
            private set;
        }

        internal WhereColumn[] WhereClauses {
            get {
                return this.where.ToArray();
            }
        }

        #endregion

        #region Constructors

        public GroupRecordQuery(IGroup group) {
            this.group = group;
            this.groupTableMap.Add(group.Id, group.SystemName);
            this.SelectColumns = this.GetSelectColumns();
        }

        public GroupRecordQuery(GroupColumn column, object whereClause) {
            this.group = Factory.Instance().GetGroup(column.BelongsToGroupId);
            this.groupTableMap.Add(group.Id, group.SystemName);
            this.SelectColumns = this.GetSelectColumns();
            this.AddWhereClause(column, whereClause);
        }

        #endregion

        #region Methods

        public void SetProcedureName(string procedure) {
            this.query = new ProcedureQuery(procedure);
            this.type = QueryType.ResultAsProcedure;
        }

        public void AddProcedureParameter(string name, object value) {
            this.query.AddParameter(name, value);
        }

        public void AddProcedureParameter(string name, object value, DbType type) {
            this.query.AddParameter(name, value, type);
        }

        public void AddWhereClause(int columnId, object clause) {
            GroupColumn col = this.group.Columns.FirstOrDefault(gc => gc.ColumnId == columnId);
            if (col == null)
                throw new ArgumentNullException(string.Format("W zbiorze {0} nie ma kolumny o id={1}!", this.group.SystemName, columnId));
            this.AddWhereClause(col, clause);
        }

        public void AddWhereClause(string columnName, object clause) {
            GroupColumn col = this.group.Columns.FirstOrDefault(gc => gc.SelectColumnName == columnName);
            if (col == null)
                throw new ArgumentNullException(string.Format("W zbiorze {0} nie ma kolumny {1}!", this.group.SystemName, columnName));
            this.AddWhereClause(col, clause);
        }

        public void AddWhereClause(GroupColumn column, object clause) {
            if (column != null) {
                WhereColumn wc = new WhereColumn(this.GetTableName(column), column.SelectColumnName, clause, column.DataType);
                this.where.Add(wc);
            }
            this.type = QueryType.QueryWithWhereClauses;
        }

        internal SelectColumn[] GetSelectColumns() {
            //return this.group.Columns.Where(gc => gc.BelongsToGroupId == this.group.Id).Select(c => GetSelectColumn(c)).Where(cn => !string.IsNullOrEmpty(cn.ColumnName)).ToArray();
            return this.group.Columns.Select(c => GetSelectColumn(c)).Where(cn => !string.IsNullOrEmpty(cn.ColumnName)).ToArray();
        }

        private SelectColumn GetSelectColumn(GroupColumn column) {
            SelectColumn sc = new SelectColumn(column.ColumnId, this.GetTableName(column), column.SelectColumnName, false);
            if (column.ColumnType == FieldType.ValueField && column.DataType == typeof(string))
                sc.TranslateSupport = true;
            return sc;
        }

        private string GetTableName(GroupColumn column) {
            if (!this.groupTableMap.ContainsKey(column.BelongsToGroupId)) {
                IGroup group = Factory.Instance().GetGroup(column.BelongsToGroupId);
                if (group == null || !group.Exists)
                    throw new SelectRecordException(3001);
                this.groupTableMap.Add(group.Id, group.SystemName);
            }
            return this.groupTableMap[column.BelongsToGroupId];
        }

        #endregion

        #region Inner

        public enum QueryType {
            QueryWithWhereClauses,
            ResultAsProcedure
        }

        #endregion

    }
}
